package com.efivestar.idm.api.rest.errors;

import com.efivestar.idm.api.common.ResultDto;
import com.efivestar.idm.api.exception.AppException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.ResponseEntity.BodyBuilder;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;

import java.util.List;
import java.util.stream.Collectors;

/**
 * Controller advice to translate the server side exceptions to client-friendly json structures.
 */
@ControllerAdvice
public class ExceptionTranslator {
    /**
     * 非法参数
     */
    public static final String INVALID_PARAM = "30001";
    /**
     *参数格式异常，例如json格式有问题
     */
    public static final String INVALID_FORMAT_PARAM = "30002";

    private final static Logger log = LoggerFactory.getLogger(ExceptionTranslator.class);

    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ResponseBody
    public ResultDto processValidationError(MethodArgumentNotValidException ex) {

        BindingResult result = ex.getBindingResult();
        List<FieldError> fieldErrors = result.getFieldErrors();
        String errorMsg = fieldErrors.stream().map(d -> d.getField() + d.getDefaultMessage()).collect(Collectors.joining("|"));
        log.error("参数异常", ex);
        return ResultDto.builder().success("false").exceptionObj(new ResultDto.ExceptionObj(INVALID_PARAM, errorMsg)).build();
    }


    @ExceptionHandler({AppException.class})
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ResponseBody
    public ResultDto handleException(AppException ex) {
        log.error(ex.getCode(), ex);
        return ResultDto.builder().success("false").exceptionObj(new ResultDto.ExceptionObj(ex.getCode(), ex.getMessage())).build();
    }

    @ExceptionHandler(HttpMessageNotReadableException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ResponseBody
    public ResultDto processConcurrencyError(HttpMessageNotReadableException ex) {
        log.error(ex.getMessage(), ex);
        return ResultDto.builder().success("false").exceptionObj(new ResultDto.ExceptionObj(INVALID_FORMAT_PARAM, "参数格式异常")).build();
    }


    @ExceptionHandler(Exception.class)
    public ResponseEntity<ResultDto> processRuntimeException(Exception ex) {
        log.error(ex.getMessage(), ex);
        BodyBuilder builder;
        ResultDto resultDto;
        ResponseStatus responseStatus = AnnotationUtils.findAnnotation(ex.getClass(), ResponseStatus.class);
        if (responseStatus != null) {
            builder = ResponseEntity.status(responseStatus.value());
        } else {
            builder = ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR);
        }
        resultDto = ResultDto.builder().success("false").exceptionObj(new ResultDto.ExceptionObj("0", "系统异常")).build();
        return builder.body(resultDto);
    }
}
